home *** CD-ROM | disk | FTP | other *** search
/ AmigActive 25 / AACD 25.iso / AACD / Utilities / BasiliskII / src / disk.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2001-02-02  |  13.3 KB  |  505 lines

  1. /*
  2.  *  disk.cpp - Generic disk driver
  3.  *
  4.  *  Basilisk II (C) 1997-2001 Christian Bauer
  5.  *
  6.  *  This program is free software; you can redistribute it and/or modify
  7.  *  it under the terms of the GNU General Public License as published by
  8.  *  the Free Software Foundation; either version 2 of the License, or
  9.  *  (at your option) any later version.
  10.  *
  11.  *  This program is distributed in the hope that it will be useful,
  12.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.  *  GNU General Public License for more details.
  15.  *
  16.  *  You should have received a copy of the GNU General Public License
  17.  *  along with this program; if not, write to the Free Software
  18.  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19.  */
  20.  
  21. /*
  22.  *  SEE ALSO
  23.  *    Inside Macintosh: Devices, chapter 1 "Device Manager"
  24.  *    Technote DV 05: "Drive Queue Elements"
  25.  *    Technote DV 23: "Driver Education"
  26.  *    Technote FL 24: "Don't Look at ioPosOffset for Devices"
  27.  */
  28.  
  29. #include <string.h>
  30.  
  31. #include "sysdeps.h"
  32. #include "cpu_emulation.h"
  33. #include "main.h"
  34. #include "macos_util.h"
  35. #include "sys.h"
  36. #include "prefs.h"
  37. #include "disk.h"
  38.  
  39. #define DEBUG 0
  40. #include "debug.h"
  41.  
  42.  
  43. // .Disk Disk/drive icon
  44. const uint8 DiskIcon[258] = {
  45.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  46.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  47.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  48.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  49.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
  50.     0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
  51.     0x80, 0x00, 0x00, 0x01, 0x8c, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01, 0x80, 0x00, 0x00, 0x01,
  52.     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  53.  
  54.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  55.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  56.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  57.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  58.     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7f, 0xff, 0xff, 0xfe,
  59.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  60.     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
  61.     0x7f, 0xff, 0xff, 0xfe, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
  62.  
  63.     0, 0
  64. };
  65.  
  66.  
  67. // Struct for each drive
  68. struct DriveInfo {
  69.     DriveInfo()
  70.     {
  71.         next = NULL;
  72.         num = 0;
  73.         fh = NULL;
  74.         read_only = false;
  75.         status = 0;
  76.     }
  77.  
  78.     DriveInfo *next;    // Pointer to next DriveInfo (must be first in struct!)
  79.     int num;            // Drive number
  80.     void *fh;            // File handle
  81.     uint32 num_blocks;    // Size in 512-byte blocks
  82.     bool to_be_mounted;    // Flag: drive must be mounted in accRun
  83.     bool read_only;        // Flag: force write protection
  84.     uint32 status;        // Mac address of drive status record
  85. };
  86.  
  87. // Linked list of DriveInfos
  88. static DriveInfo *first_drive_info;
  89.  
  90. // Icon address (Mac address space, set by PatchROM())
  91. uint32 DiskIconAddr;
  92.  
  93. // Flag: Control(accRun) has been called, interrupt routine is now active
  94. static bool acc_run_called = false;
  95.  
  96.  
  97. /*
  98.  *  Get pointer to drive info, NULL = invalid drive number
  99.  */
  100.  
  101. static DriveInfo *get_drive_info(int num)
  102. {
  103.     DriveInfo *info = first_drive_info;
  104.     while (info != NULL) {
  105.         if (info->num == num)
  106.             return info;
  107.         info = info->next;
  108.     }
  109.     return NULL;
  110. }
  111.  
  112.  
  113. /*
  114.  *  Initialization
  115.  */
  116.  
  117. void DiskInit(void)
  118. {
  119.     first_drive_info = NULL;
  120.  
  121.     // No drives specified in prefs? Then add defaults
  122.     if (PrefsFindString("disk", 0) == NULL)
  123.         SysAddDiskPrefs();
  124.  
  125.     // Add drives specified in preferences
  126.     int32 index = 0;
  127.     const char *str;
  128.     while ((str = PrefsFindString("disk", index++)) != NULL) {
  129.         bool read_only = false;
  130.         if (str[0] == '*') {
  131.             read_only = true;
  132.             str++;
  133.         }
  134.         void *fh = Sys_open(str, read_only);
  135.         if (fh) {
  136.             D(bug(" adding drive '%s'\n", str));
  137.             DriveInfo *info = new DriveInfo;
  138.             info->fh = fh;
  139.             info->read_only = SysIsReadOnly(fh);
  140.             DriveInfo *p = (DriveInfo *)&first_drive_info;
  141.             while (p->next != NULL)
  142.                 p = p->next;
  143.             p->next = info;
  144.         }
  145.     }
  146. }
  147.  
  148.  
  149. /*
  150.  *  Deinitialization
  151.  */
  152.  
  153. void DiskExit(void)
  154. {
  155.     DriveInfo *info = first_drive_info, *next;
  156.     while (info != NULL) {
  157.         Sys_close(info->fh);
  158.         next = info->next;
  159.         delete info;
  160.         info = next;
  161.     }
  162. }
  163.  
  164.  
  165. /*
  166.  *  Disk was inserted, flag for mounting
  167.  */
  168.  
  169. bool DiskMountVolume(void *fh)
  170. {
  171.     DriveInfo *info;
  172.     for (info = first_drive_info; info != NULL && info->fh != fh; info = info->next) ;
  173.     if (info) {
  174.         if (SysIsDiskInserted(info->fh)) {
  175.             info->read_only = SysIsReadOnly(info->fh);
  176.             WriteMacInt8(info->status + dsDiskInPlace, 1);    // Inserted removable disk
  177.             WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0xff : 0);
  178.             info->num_blocks = SysGetFileSize(info->fh) / 512;
  179.             WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff);
  180.             WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16);
  181.             info->to_be_mounted = true;
  182.         }
  183.         return true;
  184.     } else
  185.         return false;
  186. }
  187.  
  188.  
  189. /*
  190.  *  Mount volumes for which the to_be_mounted flag is set
  191.  *  (called during interrupt time)
  192.  */
  193.  
  194. static void mount_mountable_volumes(void)
  195. {
  196.     DriveInfo *info = first_drive_info;
  197.     while (info != NULL) {
  198.  
  199.         // Disk in drive?
  200.         if (!ReadMacInt8(info->status + dsDiskInPlace)) {
  201.  
  202.             // No, check if disk was inserted
  203.             if (SysIsDiskInserted(info->fh))
  204.                 DiskMountVolume(info->fh);
  205.         }
  206.  
  207.         // Mount disk if flagged
  208.         if (info->to_be_mounted) {
  209.             D(bug(" mounting drive %d\n", info->num));
  210.             M68kRegisters r;
  211.             r.d[0] = info->num;
  212.             r.a[0] = 7;    // diskEvent
  213.             Execute68kTrap(0xa02f, &r);        // PostEvent()
  214.             info->to_be_mounted = false;
  215.         }
  216.  
  217.         info = info->next;
  218.     }
  219. }
  220.  
  221.  
  222. /*
  223.  *  Driver Open() routine
  224.  */
  225.  
  226. int16 DiskOpen(uint32 pb, uint32 dce)
  227. {
  228.     D(bug("DiskOpen\n"));
  229.  
  230.     // Set up DCE
  231.     WriteMacInt32(dce + dCtlPosition, 0);
  232.     acc_run_called = false;
  233.  
  234.     // Install drives
  235.     for (DriveInfo *info = first_drive_info; info; info = info->next) {
  236.  
  237.         info->num = FindFreeDriveNumber(1);
  238.         info->to_be_mounted = false;
  239.  
  240.         if (info->fh) {
  241.  
  242.             // Allocate drive status record
  243.             M68kRegisters r;
  244.             r.d[0] = SIZEOF_DrvSts;
  245.             Execute68kTrap(0xa71e, &r);        // NewPtrSysClear()
  246.             if (r.a[0] == 0)
  247.                 continue;
  248.             info->status = r.a[0];
  249.             D(bug(" DrvSts at %08lx\n", info->status));
  250.  
  251.             // Set up drive status
  252.             WriteMacInt16(info->status + dsQType, hard20);
  253.             WriteMacInt8(info->status + dsInstalled, 1);
  254.             bool disk_in_place = false;
  255.             if (SysIsFixedDisk(info->fh)) {
  256.                 WriteMacInt8(info->status + dsDiskInPlace, 8);    // Fixed disk
  257.                 disk_in_place = true;
  258.             } else if (SysIsDiskInserted(info->fh)) {
  259.                 WriteMacInt8(info->status + dsDiskInPlace, 1);    // Inserted removable disk
  260.                 disk_in_place = true;
  261.             }
  262.             if (disk_in_place) {
  263.                 D(bug(" disk inserted\n"));
  264.                 WriteMacInt8(info->status + dsWriteProt, info->read_only ? 0x80 : 0);
  265.                 info->num_blocks = SysGetFileSize(info->fh) / 512;
  266.                 info->to_be_mounted = true;
  267.             }
  268.             D(bug(" %d blocks\n", info->num_blocks));
  269.             WriteMacInt16(info->status + dsDriveSize, info->num_blocks & 0xffff);
  270.             WriteMacInt16(info->status + dsDriveS1, info->num_blocks >> 16);
  271.  
  272.             // Add drive to drive queue
  273.             D(bug(" adding drive %d\n", info->num));
  274.             r.d[0] = (info->num << 16) | (DiskRefNum & 0xffff);
  275.             r.a[0] = info->status + dsQLink;
  276.             Execute68kTrap(0xa04e, &r);    // AddDrive()
  277.         }
  278.     }
  279.     return noErr;
  280. }
  281.  
  282.  
  283. /*
  284.  *  Driver Prime() routine
  285.  */
  286.  
  287. int16 DiskPrime(uint32 pb, uint32 dce)
  288. {
  289.     WriteMacInt32(pb + ioActCount, 0);
  290.  
  291.     // Drive valid and disk inserted?
  292.     DriveInfo *info;
  293.     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
  294.         return nsDrvErr;
  295.     if (!ReadMacInt8(info->status + dsDiskInPlace))
  296.         return offLinErr;
  297.  
  298.     // Get parameters
  299.     void *buffer = Mac2HostAddr(ReadMacInt32(pb + ioBuffer));
  300.     size_t length = ReadMacInt32(pb + ioReqCount);
  301.     loff_t position = ReadMacInt32(dce + dCtlPosition);
  302.     if (ReadMacInt16(pb + ioPosMode) & 0x100)    // 64 bit positioning
  303.         position = ((loff_t)ReadMacInt32(pb + ioWPosOffset) << 32) || ReadMacInt32(pb + ioWPosOffset + 4);
  304.     if ((length & 0x1ff) || (position & 0x1ff))
  305.         return paramErr;
  306.  
  307.     size_t actual = 0;
  308.     if ((ReadMacInt16(pb + ioTrap) & 0xff) == aRdCmd) {
  309.  
  310.         // Read
  311.         actual = Sys_read(info->fh, buffer, position, length);
  312.         if (actual != length)
  313.             return readErr;
  314.  
  315.     } else {
  316.  
  317.         // Write
  318.         if (info->read_only)
  319.             return wPrErr;
  320.         actual = Sys_write(info->fh, buffer, position, length);
  321.         if (actual != length)
  322.             return writErr;
  323.     }
  324.  
  325.     // Update ParamBlock and DCE
  326.     WriteMacInt32(pb + ioActCount, actual);
  327.     WriteMacInt32(dce + dCtlPosition, ReadMacInt32(dce + dCtlPosition) + actual);
  328.     return noErr;
  329. }
  330.  
  331.  
  332. /*
  333.  *  Driver Control() routine
  334.  */
  335.  
  336. int16 DiskControl(uint32 pb, uint32 dce)
  337. {
  338.     uint16 code = ReadMacInt16(pb + csCode);
  339.     D(bug("DiskControl %d\n", code));
  340.  
  341.     // General codes
  342.     switch (code) {
  343.         case 1:        // KillIO
  344.             return noErr;
  345.  
  346.         case 65: {    // Periodic action (accRun, "insert" disks on startup)
  347.             mount_mountable_volumes();
  348.             WriteMacInt16(dce + dCtlFlags, ReadMacInt16(dce + dCtlFlags) & ~0x2000);    // Disable periodic action
  349.             acc_run_called = true;
  350.             return noErr;
  351.         }
  352.     }
  353.  
  354.     // Drive valid?
  355.     DriveInfo *info;
  356.     if ((info = get_drive_info(ReadMacInt16(pb + ioVRefNum))) == NULL)
  357.         return nsDrvErr;
  358.  
  359.     // Drive-specific codes
  360.     switch (code) {
  361.         case 5:        // Verify disk
  362.             if (ReadMacInt8(info->status + dsDiskInPlace) > 0)
  363.                 return noErr;
  364.             else
  365.                 return offLinErr;
  366.  
  367.         case 6:        // Format disk
  368.             if (info->read_only)
  369.                 return wPrErr;
  370.             else if (ReadMacInt8(info->status + dsDiskInPlace) > 0)
  371.                 return noErr;
  372.             else
  373.                 return offLinErr;
  374.  
  375.         case 7:        // Eject disk
  376.             if (ReadMacInt8(info->status + dsDiskInPlace) == 8) {
  377.                 // Fixed disk, re-insert
  378.                 M68kRegisters r;
  379.                 r.d[0] = info->num;
  380.                 r.a[0] = 7;    // diskEvent
  381.                 Execute68kTrap(0xa02f, &r);        // PostEvent()
  382.             } else if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
  383.                 SysEject(info->fh);
  384.                 WriteMacInt8(info->status + dsDiskInPlace, 0);
  385.             }
  386.             return noErr;
  387.  
  388.         case 21:    // Get drive icon
  389.         case 22:    // Get disk icon
  390.             WriteMacInt32(pb + csParam, DiskIconAddr);
  391.             return noErr;
  392.  
  393.         case 23:    // Get drive info
  394.             if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
  395.                 WriteMacInt32(pb + csParam, 0x0601);    // Unspecified fixed SCSI disk
  396.             else
  397.                 WriteMacInt32(pb + csParam, 0x0201);    // Unspecified SCSI disk
  398.             return noErr;
  399.  
  400.         case 24:    // Get partition size
  401.             if (ReadMacInt8(info->status + dsDiskInPlace) > 0) {
  402.                 WriteMacInt32(pb + csParam, info->num_blocks);
  403.                 return noErr;
  404.             } else
  405.                 return offLinErr;
  406.  
  407.         default:
  408.             printf("WARNING: Unknown DiskControl(%d)\n", code);
  409.             return controlErr;
  410.     }
  411. }
  412.  
  413.  
  414. /*
  415.  *  Driver Status() routine
  416.  */
  417.  
  418. int16 DiskStatus(uint32 pb, uint32 dce)
  419. {
  420.     DriveInfo *info = get_drive_info(ReadMacInt16(pb + ioVRefNum));
  421.     uint16 code = ReadMacInt16(pb + csCode);
  422.     D(bug("DiskStatus %d\n", code));
  423.  
  424.     // General codes
  425.     switch (code) {
  426.         case 43: {    // Driver gestalt
  427.             uint32 sel = ReadMacInt32(pb + csParam);
  428.             D(bug(" driver gestalt %c%c%c%c\n", sel >> 24, sel >> 16,  sel >> 8, sel));
  429.             switch (sel) {
  430.                 case FOURCC('v','e','r','s'):    // Version
  431.                     WriteMacInt32(pb + csParam + 4, 0x01008000);
  432.                     break;
  433.                 case FOURCC('d','e','v','t'):    // Device type
  434.                     if (info != NULL) {
  435.                         if (ReadMacInt8(info->status + dsDiskInPlace) == 8)
  436.                             WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
  437.                         else
  438.                             WriteMacInt32(pb + csParam + 4, FOURCC('r','d','s','k'));
  439.                     } else
  440.                         WriteMacInt32(pb + csParam + 4, FOURCC('d','i','s','k'));
  441.                     break;
  442.                 case FOURCC('i','n','t','f'):    // Interface type
  443.                     WriteMacInt32(pb + csParam + 4, EMULATOR_ID_4);
  444.                     break;
  445.                 case FOURCC('s','y','n','c'):    // Only synchronous operation?
  446.                     WriteMacInt32(pb + csParam + 4, 0x01000000);
  447.                     break;
  448.                 case FOURCC('b','o','o','t'):    // Boot ID
  449.                     if (info != NULL)
  450.                         WriteMacInt16(pb + csParam + 4, info->num);
  451.                     else
  452.                         WriteMacInt16(pb + csParam + 4, 0);
  453.                     WriteMacInt16(pb + csParam + 6, (uint16)DiskRefNum);
  454.                     break;
  455.                 case FOURCC('w','i','d','e'):    // 64-bit access supported?
  456.                     WriteMacInt16(pb + csParam + 4, 0x0100);
  457.                     break;
  458.                 case FOURCC('p','u','r','g'):    // Purge flags
  459.                     WriteMacInt32(pb + csParam + 4, 0);
  460.                     break;
  461.                 case FOURCC('e','j','e','c'):    // Eject flags
  462.                     WriteMacInt32(pb + csParam + 4, 0x00030003);    // Don't eject on shutdown/restart
  463.                     break;
  464.                 case FOURCC('f','l','u','s'):    // Flush flags
  465.                     WriteMacInt16(pb + csParam + 4, 0);
  466.                     break;
  467.                 case FOURCC('v','m','o','p'):    // Virtual memory attributes
  468.                     WriteMacInt32(pb + csParam + 4, 0);    // Drive not available for VM
  469.                     break;
  470.                 default:
  471.                     return statusErr;
  472.             }
  473.             return noErr;
  474.         }
  475.     }
  476.  
  477.     // Drive valid?
  478.     if (info == NULL)
  479.         return nsDrvErr;
  480.  
  481.     // Drive-specific codes
  482.     switch (code) {
  483.         case 8:        // Get drive status
  484.             Mac2Mac_memcpy(pb + csParam, info->status, 22);
  485.             return noErr;
  486.  
  487.         default:
  488.             printf("WARNING: Unknown DiskStatus(%d)\n", code);
  489.             return statusErr;
  490.     }
  491. }
  492.  
  493.  
  494. /*
  495.  *  Driver interrupt routine (1Hz) - check for volumes to be mounted
  496.  */
  497.  
  498. void DiskInterrupt(void)
  499. {
  500.     if (!acc_run_called)
  501.         return;
  502.  
  503.     mount_mountable_volumes();
  504. }
  505.